package cc.shacocloud.mirage.bean.impl;

import cc.shacocloud.mirage.bean.QualifierHandler;
import cc.shacocloud.mirage.bean.ScopeHandler;
import cc.shacocloud.mirage.bean.bind.Autowired;
import cc.shacocloud.mirage.bean.bind.Bean;
import cc.shacocloud.mirage.bean.bind.Component;
import cc.shacocloud.mirage.bean.meta.BeanKey;
import cc.shacocloud.mirage.bean.meta.ProviderBeanKey;
import cc.shacocloud.mirage.utils.ClassUtil;
import cc.shacocloud.mirage.utils.MethodParameter;
import cc.shacocloud.mirage.utils.ResolvableType;
import cc.shacocloud.mirage.utils.annotation.AnnotatedElementUtils;
import cc.shacocloud.mirage.utils.reflection.ReflectUtil;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 针对 {@link cc.shacocloud.mirage.bean.bind.Component} 声明的bean的一些方法操作定义
 *
 * @author 思追(shaco)
 */
public abstract class AbstractBeanHandler {
    
    protected static final Class<Inject> INJECTION_ANNOTATION = Inject.class;
    protected static final Class<Autowired> AUTOWIRED_ANNOTATION = Autowired.class;
    protected static final Class<Bean> BEAN_ANNOTATION = Bean.class;
    protected static final Class<Component> COMPONENT_ANNOTATION = Component.class;
    
    @NotNull
    protected final QualifierHandler qualifierHandler;
    
    @NotNull
    protected final ScopeHandler scopeHandler;
    
    public AbstractBeanHandler(@NotNull QualifierHandler qualifierHandler,
                               @NotNull ScopeHandler scopeHandler) {
        this.qualifierHandler = qualifierHandler;
        this.scopeHandler = scopeHandler;
    }
    
    /**
     * 获取可执行的对象参数的 {@link BeanKey} 形式
     *
     * @see Constructor
     * @see Method
     */
    protected List<BeanKey> getExecutableParameters(@NotNull Executable executable) {
        int count = executable.getParameterCount();
        
        List<BeanKey> dependencies = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            MethodParameter methodParameter;
            
            if (executable instanceof Constructor) {
                methodParameter = new MethodParameter((Constructor<?>) executable, i);
            } else if (executable instanceof Method) {
                methodParameter = new MethodParameter((Method) executable, i);
            } else {
                throw new UnsupportedOperationException("不支持的类型：" + executable);
            }
            
            ResolvableType methodType = ResolvableType.forMethodParameter(methodParameter);
            
            // 判断是否必须的，默认是必须的
            Autowired autowired = AnnotatedElementUtils.getAnnotation(methodParameter.getParameter(), Autowired.class);
            boolean required = Objects.isNull(autowired) || autowired.required();
            
            String qualifier = qualifierHandler.getQualifier(methodParameter.getParameter());
            BeanKey beanKey = createBeanKey(methodType, qualifier, required);
            dependencies.add(beanKey);
        }
        
        return dependencies;
    }
    
    /**
     * 创建 {@link BeanKey}
     */
    protected @NotNull BeanKey createBeanKey(@NotNull ResolvableType type,
                                             @Nullable String qualifier,
                                             boolean required) {
        BeanKey beanKey;
        if (isProvider(type)) {
            beanKey = new ProviderBeanKey(type, qualifier, required);
        } else {
            beanKey = new BeanKey(type, qualifier, required);
        }
        return beanKey;
    }
    
    /**
     * 是否为提供者类型
     *
     * @see Provider
     */
    protected boolean isProvider(@NotNull ResolvableType type) {
        Class<?> rawClass = type.getRawClass();
        return Objects.nonNull(rawClass) && ClassUtil.isAssignable(Provider.class, rawClass);
    }
    
    /**
     * 判断字段是否需要注入
     */
    protected boolean isFieldNeedsInjection(@NotNull Field field) {
        return !ReflectUtil.isStatic(field)
                && !ReflectUtil.isFinal(field)
                && (field.isAnnotationPresent(INJECTION_ANNOTATION) || field.isAnnotationPresent(AUTOWIRED_ANNOTATION));
    }
    
    /**
     * 判断方法是否需要注入
     */
    protected boolean isMethodNeedsInjection(final Method method) {
        return !ReflectUtil.isStatic(method)
                && ReflectUtil.isPublic(method)
                && (method.isAnnotationPresent(INJECTION_ANNOTATION) || method.isAnnotationPresent(AUTOWIRED_ANNOTATION));
    }
    
    /**
     * 判断构造函数是否需要注入
     */
    protected boolean isConstructorNeedsInjection(@NotNull Constructor<?> constructor) {
        return ReflectUtil.isPublic(constructor)
                && (constructor.isAnnotationPresent(INJECTION_ANNOTATION) || constructor.isAnnotationPresent(AUTOWIRED_ANNOTATION));
    }
    
}
